import axios, { type AxiosRequestHeaders, type AxiosResponse } from 'axios';
import { ElMessage, ElMessageBox } from 'element-plus';
import pinia from '@/stores/index';
// 1. 引入 useUserInfoStore 获取整个store
import { useUserInfoStore } from '../stores/userInfo';

// 配置新建一个 axios 实例
const service = axios.create({
	// 根据环境自动化的选择配置的环境变量  
	// 开发环境：'/app-dev'   
	// 生成环境：'/app-prod'
	baseURL: import.meta.env.VITE_API_URL, 
	timeout: 50000,
});

// 添加请求拦截器--一般不会配置失败的
service.interceptors.request.use(
	(config) => {
		// 要么添加额外功能

		// 要么携带请求头
    let token = useUserInfoStore(pinia).token
		// 判断是否拿到token
		if(token){
			// 2.把拿到的token携带到请求头当中去
			(config.headers as AxiosRequestHeaders).token = token
		}

		// 请求头这必须return config 因为成功了才会继续往下传
		return config;
	}
);

/* *************************************************************** */
// 这个对象的类型 axios已经给你定义好了，就是AxiosResponse，我们已经引入
// 如果我们只是为了限定这个response整体，那么就直接这样写即可(response: AxiosResponse) => {}
// 但是这个response当中有一个data属性，data属性就是我们要的数据所在的对象
// 它是后台人员给我们设定好的一个对象，里面的东西也是固定的额，只是值不同
// 我们要对这个response.data做一个限定,对这个data我们是要定义一个接口去做限定
// 定义reaponse.data的接口
// interface ResponseData{
//   code: number;
//   data: ？？？;
//   message: string;
// }

// 去限定response.data的时候使用上面定义的接口去限定，但是我们还发现data当中还有个data,
// 这个data（response.data.data）是我们真正的请求不同接口回来的数据， 它也要去限定类型，而这个类型我们又不确定是什么类型
// 因此在定义response.data的接口的时候，就要考虑，response.data.data的类型，所以接口就得改为接口泛型
// response:{
// 	data:{
// 		data:数据
// 	}
// }
// 1.定义response对象的response.data接口和response.data.data的泛型
interface ResponseData<T> {
  code: number;
  data: T;
  message: string;
}

/* 1. 定义函数的时候定义泛型 */
// 1.定义的时候fn是T
// 2.形参a 是T
// 3.返回的是T
// function fn<T>(a:T):T{
// 	return a
// }
/* 2. 使用函数的时候确定泛型 */
// 使用的时候是什么类型就传什么类型
// fn<number>(100)
// fn<string>('111')
/* *************************************************************** */

// 添加响应拦截器
service.interceptors.response.use(
  /* 约束一下response */
	// AxiosResponse 										限定response
	// AxiosResponse<ResponseData> 			限定response.data
	// AxiosResponse<ResponseData<any>> 限定response.data.data
	// 2. 使用的时候确定泛型
	async (response: AxiosResponse<ResponseData<any>>) => {
		// 对响应数据做点什么
		const res = response.data;
    if (res.code !== 20000 && res.code !== 200) { /* 成功数据的code值为20000/200 */
      // 统一的错误提示
      ElMessage({
        message: (typeof res.data=='string' && res.data) || res.message || 'Error',
        type: 'error',
        duration: 5 * 1000
      })

			// // `token` 过期或者账号已在别处登录
      // if (response.status===401) {
      //   const storeUserInfo = useUserInfoStore(pinia)
			// 	await storeUserInfo.reset()
			// 	window.location.href = '/' // 去登录页
			// 	ElMessageBox.alert('你已被登出，请重新登录', '提示', {})
			// 		.then(() => {})
			// 		.catch(() => {})
			// }
			return Promise.reject(service.interceptors.response);
		} else {
      return res.data; /* 返回成功响应数据中的data属性数据 */
		}
	},
	(error) => {
		/* *****************详细写法*****************************
		// 对响应错误做点什么
		if (error.message.indexOf('timeout') != -1) {
			// 如果错误消息以timeout开头 就弹框 网络超时
			ElMessage.error('网络超时');
		} else if (error.message == 'Network Error') {
			// 如果错误消息以Network Error开头 就弹框 网络连接错误
			ElMessage.error('网络连接错误');
		} else {
			if (error.response.data) ElMessage.error(error.response.statusText);
			else ElMessage.error('接口路径找不到');
		}
		// 如果上面都不是就继续把错误往下传
		return Promise.reject(error); 
		******************************************************** */

		/* ****************统一处理错误写法********************* */
		ElMessage.error('发送ajax请求失败' + error.message) 
		return Promise.reject(error);
	}
);

export default service;
